﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Excel2DbTool.Models
{

    public interface IDbFieldVal
    {
        Object Val { get; set; }
    }

    /// <summary>
    /// 原有数据库中的字段映射到目标数据库中的某个字段
    /// 实例化子类时请根据字段在目标数据库中的字段来选择子类类型
    /// </summary>
    public abstract class DbFieldMapping : IDbFieldVal
    {

        public DbFieldMapping(string orignFieldName, string targetFieldName)
        {
            this.OrignFieldName = orignFieldName;
            this.TargetFieldName = targetFieldName;
        }

        public string OrignFieldName { get; private set; }
        public string TargetFieldName { get; private set; }

        public abstract IDbFieldVal GetDbFieldVal();

        public abstract object Val { get; set; }

        public abstract DbFieldMapping Clone();

        public static readonly string StrEmpty = "' '";
        public static readonly string NumEmpty = "null";
        public static readonly string NotNumEmpty = "0";
    }

    public class OracleTableStrField : DbFieldMapping
    {
        public OracleTableStrField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {

        }

        private object val;
        public override object Val
        {
            get
            {
                return string.Format("'{0}'", val == null ? " " : val);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableStrField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableStrField(this.OrignFieldName, this.TargetFieldName);
            otfield.val = this.val;
            return otfield;
        }
    }

    public class OracleTableNotNullStrField : OracleTableStrField
    {
        public OracleTableNotNullStrField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {

        }

        private object val;
        public override object Val
        {
            get
            {
                return string.Format("'{0}'", (val == null || val == DBNull.Value) ? " " : val);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableNotNullStrField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableNotNullStrField(this.OrignFieldName, this.TargetFieldName);
            otfield.val = this.val;
            return otfield;
        }

    }

    public class OracleTableNumField : DbFieldMapping
    {
        public OracleTableNumField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {

        }

        private object val;
        public override object Val
        {
            get
            {
                if (Excel2DbTool.Helpers.DigitHelper.IsDigit(val.ToString()))
                {
                    return val;
                }
                else
                {
                    return "null";
                }
                //return string.Format("{0}", val == null ? DBNull.Value : val);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableNumField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableNumField(this.OrignFieldName, this.TargetFieldName);
            otfield.Val = this.val;
            return otfield;
        }
    }

    public class OracleTableNotNullNumField : OracleTableNumField
    {
        public OracleTableNotNullNumField(string orignFieldName, string targetFieldName, double defaultVal = 0)
            : base(orignFieldName, targetFieldName)
        {
            this.Val = defaultVal;
        }

        private object val;
        public override object Val
        {
            get
            {
                return string.Format("{0}", val == null ? 0 : val);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableNotNullNumField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableNotNullNumField(this.OrignFieldName, this.TargetFieldName);

            return otfield;
        }

    }

    public class OracleTableDateTimeField : DbFieldMapping
    {
        public OracleTableDateTimeField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {

        }

        private object val;
        public override object Val
        {
            get
            {
                if (val == null || val == DBNull.Value)
                {
                    return "null";
                }
                else
                {
                    DateTime dateTime = DateTime.Now; 
                    try
                    {
                       dateTime =  ((DateTime)(Convert.ChangeType(val, typeof(DateTime))));
                    }
                    catch (FormatException e)
                    {
                        Debug.WriteLine(this.OrignFieldName);
                        Debug.WriteLine(this.TargetFieldName);
                        Debug.WriteLine(val);
                        throw;
                    }
                    
                    return String.Format("TO_DATE('{0}','{1}')", dateTime.ToString("yyyy-M-dd"), "yyyy-MM-dd");
                }
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableDateTimeField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableDateTimeField(this.OrignFieldName, this.TargetFieldName);
            otfield.Val = this.val;
            return otfield;
        }
    }


    public abstract class OracleTableIdentityField : DbFieldMapping
    {
        public OracleTableIdentityField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {
        }

    }

    public class OracleTableIdentityStrField : OracleTableIdentityField
    {
        private int length = 0;


        public OracleTableIdentityStrField(string orignFieldName, string targetFieldName, int length = 36)
            : base(orignFieldName, targetFieldName)
        {
            this.length = length;
        }


        private object val;
        public override object Val
        {
            get
            {
                return string.Format("'{0}'", val == null ? GetIdentityValAndChangeThePrivateField_val() : val);
            }
            set
            {
                val = value;
            }
        }


        string GetIdentityValAndChangeThePrivateField_val()
        {
            val = Guid.NewGuid().ToString().Replace("-", "~").Substring(0, length);
            return val.ToString();
        }


        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableIdentityStrField(null, null, length);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableIdentityStrField(this.OrignFieldName, this.TargetFieldName, length);

            return otfield;
        }
    }

    public class OracleTableReferenceKeyField : DbFieldMapping
    {
        public OracleTableReferenceKeyField(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {
        }

        private object val;
        public override object Val
        {
            get
            {
                if (val == null)
                {
                    return DBNull.Value;
                }
                else
                {
                    return val;
                }
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableReferenceKeyField(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableReferenceKeyField(this.OrignFieldName, this.TargetFieldName);
            otfield.Val = this.Val;
            return otfield;
        }
    }

    public class OrcleTableSelfIncreaseField_ZRZH : DbFieldMapping
    {
        static int FLAG = 1;

        public OrcleTableSelfIncreaseField_ZRZH(string orignFieldName, string targetFieldName)
            : base(orignFieldName, targetFieldName)
        {
        }

        private object val;
        public override object Val
        {
            get
            {
                if (val == null || val == DBNull.Value)
                {
                    GetUniqueFLAG();
                    string result = FLAG.ToString("D5");
                    return string.Format("'{0}'", result);
                }
                return val;
            }
            set
            {
                val = value;
            }
        }

        void GetUniqueFLAG()
        {
            string value = Excel2DbTool.Common.SqlHelper.GetInstance().GetStatisticVal<string>("SELECT MAX(zrzh) FROM bdc_zrz");

            int valParsed;
            bool parseTOF = int.TryParse(value, out valParsed);
            if (parseTOF)
            {
                FLAG = int.Parse(value) + 1;
            }
            else
            {
                FLAG += 1;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OrcleTableSelfIncreaseField_ZRZH(null, null);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OrcleTableSelfIncreaseField_ZRZH(this.OrignFieldName, this.TargetFieldName);
            otfield.Val = this.val;
            return otfield;
        }
    }

    public class OrcleTableFieldMappgingToDbSysDict : DbFieldMapping
    {
        Excel2DbTool.Helpers.DbDict dbDict = null;

        public OrcleTableFieldMappgingToDbSysDict(string orignFieldName, string targetFieldName, Excel2DbTool.Helpers.DbDict dbDict)
            : base(orignFieldName, targetFieldName)
        {
            this.dbDict = dbDict;
        }

        private object val;
        public override object Val
        {
            get
            {
                if (val == null || val == DBNull.Value)
                {
                    return "null";
                }

                return dbDict[val.ToString()];
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OrcleTableFieldMappgingToDbSysDict(null, null, this.dbDict);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OrcleTableFieldMappgingToDbSysDict(this.OrignFieldName, this.TargetFieldName, this.dbDict);
            otfield.Val = this.val;
            return otfield;
        }
    }

    //引用其他表中的字段的值
    public class OracleTableStrFieldReferToOtherTable : OracleTableStrField
    {
        public OracleTableStrFieldReferToOtherTable(string orignFieldName, string targetFieldName, string otherTableName,string otherTableFieldName)
            : base(orignFieldName, targetFieldName)
        {
            this.OtherTableName = otherTableName;
            this.OtherTableFieldName = otherTableFieldName;
        }

        public string OtherTableName { get; private set; }
        public string OtherTableFieldName { get; private set; }

        private object val;
        public override object Val
        {
            get
            {
                return string.Format("'{0}'", val == null ? " " : val);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableStrFieldReferToOtherTable(null, null, OtherTableName, OtherTableFieldName);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableStrFieldReferToOtherTable(this.OrignFieldName, this.TargetFieldName, OtherTableName, OtherTableFieldName);
            otfield.val = this.val;
            return otfield;
        }
    }

    public class OracleTableStrFieldReferToOtherFieldInSameTable : OracleTableStrField
    {
       public readonly Func<string, string> Deal;

        /// <param name="orignFieldName"></param>
        /// <param name="targetFieldName"></param>
        /// <param name="fieldNameReferTo">引用的相同的表中的其它字段的字段的名称</param>
        /// <param name="deal">进行特殊处理的函数;第一个参数是OtherField对应的值,返回值为本field将被设置为的值</param>
        public OracleTableStrFieldReferToOtherFieldInSameTable(string orignFieldName, string targetFieldName, string fieldNameReferTo, Func
            <string, string> deal)
            : base(orignFieldName, targetFieldName)
        {
            this.Deal = deal;
            this.fieldNameReferTo = fieldNameReferTo;
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableStrFieldReferToOtherFieldInSameTable(null, null, this.fieldNameReferTo, Deal);
        }

        private object val;
        public override object Val
        {
            get
            {
                return (val == null || val == DBNull.Value) ? "" : val;
            }
            set
            {
                val = value;
            }
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableStrFieldReferToOtherFieldInSameTable(this.OrignFieldName, this.TargetFieldName, this.fieldNameReferTo, this.Deal);
            otfield.val = this.val;
            return otfield;
        }

        string fieldNameReferTo;
        public string FieldNameReferTo
        {
            get { return fieldNameReferTo; }
        }
    }

    public class OracleTableFieldEqualMultiExcelFieldVal : OracleTableStrField
    {
        public readonly Func<IEnumerable<string>, string> Deal;

        /// <param name="fieldNameReferTos">引用的Excel表中的其它字段的字段的名称</param>
        /// <param name="deal">进行特殊处理的函数;第一个参数是OtherField对应的值,返回值为本field将被设置为的值</param>
        public OracleTableFieldEqualMultiExcelFieldVal(string orignFieldName, string targetFieldName, IEnumerable<string> fieldNamesReferTo, Func
            <IEnumerable<string>, string> deal)
            : base(orignFieldName, targetFieldName)
        {
            this.Deal = deal;
            this.fieldNamesReferTo = fieldNamesReferTo;
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableFieldEqualMultiExcelFieldVal(null, null, this.fieldNamesReferTo, Deal);
        }

        private object val;
        public override object Val
        {
            get
            {
                return (val == null || val == DBNull.Value) ? "" : val;
            }
            set
            {
                val = value;
            }
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableFieldEqualMultiExcelFieldVal(this.OrignFieldName, this.TargetFieldName, this.fieldNamesReferTo, this.Deal);
            otfield.val = this.val;
            return otfield;
        }

        IEnumerable<string> fieldNamesReferTo;
        public IEnumerable<string> FieldNameReferTo
        {
            get { return fieldNamesReferTo; }
        }
    }

    public class OracleTableStrFieldHasFixedVal : OracleTableStrField
    {
        private string fixedVal;
        public OracleTableStrFieldHasFixedVal(string orignFieldName, string targetFieldName,string fixedVal)
            : base(orignFieldName, targetFieldName)
        {
            this.fixedVal = fixedVal;
        }

        private object val;
        public override object Val
        {
            get
            {
                return string.Format("'{0}'", fixedVal);
            }
            set
            {
                val = value;
            }
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableStrFieldHasFixedVal(null, null, fixedVal);
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableStrFieldHasFixedVal(this.OrignFieldName, this.TargetFieldName, fixedVal);
            return otfield;
        }
    }

    public class OracleTableStrFieldHasSpecialDeal : OracleTableStrField
    {
        public readonly Func<string> Deal;

        /// <param name="orignFieldName"></param>
        /// <param name="targetFieldName"></param>
        /// <param name="deal">进行特殊处理的函数;第一个参数是OtherField对应的值,返回值为本field将被设置为的值</param>
        public OracleTableStrFieldHasSpecialDeal(string orignFieldName, string targetFieldName, Func
            <string> deal)
            : base(orignFieldName, targetFieldName)
        {
            this.Deal = deal;
        }

        public override IDbFieldVal GetDbFieldVal()
        {
            return new OracleTableStrFieldHasSpecialDeal(null, null, Deal);
        }

        private object val;
        public override object Val
        {
            get
            {
                return (val == null || val == DBNull.Value) ? "" : val;
            }
            set
            {
                val = value;
            }
        }

        public override DbFieldMapping Clone()
        {
            var otfield = new OracleTableStrFieldHasSpecialDeal(this.OrignFieldName, this.TargetFieldName, this.Deal);
            otfield.val = this.val;
            return otfield;
        }
    }
}
